﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.Security;
using Microsoft.Practices.ServiceLocation;
using Microsoft.Practices.Unity;
using NCP.Recruiting.WebApp.Authentication;
using NCP.Recruiting.WebApp.Models;
using NCP.Recruiting.WebApp.UnityExtensions;

namespace NCP.Recruiting.WebApp {
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801
    public class MvcApplication : System.Web.HttpApplication {
        private static IUnityContainer container;


        public override void Init() {
            this.PostAuthenticateRequest += this.PostAuthenticateRequestHandler;
            this.EndRequest += this.EndRequestHandler;

            base.Init();
        }

        protected void Application_Start() {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            InitializeDependencyInjectionContainer();
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability",
           "CA2000:Dispose objects before losing scope",
           Justification = "This should survive the lifetime of the application.")]
        private static void InitializeDependencyInjectionContainer() {
            container = new UnityContainerFactory().CreateConfiguredContainer();
            var serviceLocator = new UnityServiceLocator(container);
            ServiceLocator.SetLocatorProvider(() => serviceLocator);
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }


        private void EndRequestHandler(object sender, EventArgs e) {
            // This is a workaround since subscribing to HttpContext.Current.ApplicationInstance.EndRequest 
            // from HttpContext.Current.ApplicationInstance.BeginRequest does not work. 
            IEnumerable<UnityHttpContextPerRequestLifetimeManager> perRequestManagers =
                container.Registrations
                    .Select(r => r.LifetimeManager)
                    .OfType<UnityHttpContextPerRequestLifetimeManager>()
                    .ToArray();

            foreach (var manager in perRequestManagers) {
                manager.Dispose();
            }
        }

        private void PostAuthenticateRequestHandler(object sender, EventArgs e) {
            HttpCookie authCookie = this.Context.Request.Cookies[FormsAuthentication.FormsCookieName];
            if (IsValidAuthCookie(authCookie)) {
                var formsAuthentication = ServiceLocator.Current.GetInstance<IFormsAuthentication>();

                var ticket = formsAuthentication.Decrypt(authCookie.Value);
                var recruitingStatsIdentity = new RecruitingIdentity(ticket);
                this.Context.User = new GenericPrincipal(recruitingStatsIdentity, null);

                // Reset cookie for a sliding expiration.
                formsAuthentication.SetAuthCookie(this.Context, ticket);
            }
        }

        private static bool IsValidAuthCookie(HttpCookie authCookie) {
            return authCookie != null && !String.IsNullOrEmpty(authCookie.Value);
        }
    }
}